( function() {
	// region 库
	var Box = Z.element.Box;
	var Label = Z.element.Label;

	// region 工具

	// 数组辅助函数
	add2list = function( list, object ) {
		list[list.length] = object;
	};

	// 辅助函数：循环取值
	var cycAt = function( arr, id ) {
		return arr[id % arr.length];
	};

	// 循环函数
	var loop = function( total, task ) {
		var p;
		for ( p = 0; p < total; p++ ) {
			task( p );
		}
	};
	var foreach = function( li, task ) {
		var p;
		for ( p in li ) {
			task( li[p] );
		}
	};

	// region 常数

	// 逻辑坐标系
	var LOGIC_WIDTH = 10;
	var LOGIC_HEIGHT = 20;

	// 砖块像素大小
	var BRIC_WIDTH = 20;
	var BRIC_HEIGHT = 20;

	// 各区域像素大小
	var GAP = 10;
	var GAME_WIDTH = LOGIC_WIDTH * BRIC_WIDTH;
	var GAME_HEIGHT = LOGIC_HEIGHT * BRIC_HEIGHT;
	var SCORE_WIDTH = 200;
	var SCORE_HEIGHT = 300;
	var TITLE_HEIGHT = 60;
	var TITLE_WIDTH = GAME_WIDTH + GAP + SCORE_WIDTH;
	var APP_WIDTH = GAP + TITLE_WIDTH + GAP;
	var APP_HEIGHT = GAP + TITLE_HEIGHT + GAP + GAME_HEIGHT + GAP;

	// 控制码
	var UP_KEY = 87;
	var DOWN_KEY = 83;
	var LEFT_KEY = 65;
	var RIGHT_KEY = 68;

	// 4块组模板
	var xy = function( x, y ) {
		return {
			x : x,
			y : y
		};
	};
	B4_TMPLS = [
			// I
			[[xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 1, 3 )], [xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 3, 1 )]],
			// J
			[[xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 2, 2 )], [xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 0, 2 )],
					[xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 0, 0 )], [xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 2, 0 )]],
			// L
			[[xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 0, 2 )], [xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 0, 0 )],
					[xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 2, 0 )], [xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 2, 2 )]],
			// S
			[[xy( 0, 1 ), xy( 1, 1 ), xy( 1, 0 ), xy( 2, 0 )], [xy( 0, 0 ), xy( 0, 1 ), xy( 1, 1 ), xy( 1, 2 )]],
			// Z
			[[xy( 0, 0 ), xy( 1, 0 ), xy( 1, 1 ), xy( 2, 1 )], [xy( 1, 0 ), xy( 1, 1 ), xy( 0, 1 ), xy( 0, 2 )]],
			// O
			[[xy( 0, 0 ), xy( 0, 1 ), xy( 1, 0 ), xy( 1, 1 )]],
			// T
			[[xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 1, 2 )], [xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 2, 1 )],
					[xy( 0, 1 ), xy( 1, 1 ), xy( 2, 1 ), xy( 1, 0 )], [xy( 1, 0 ), xy( 1, 1 ), xy( 1, 2 ), xy( 0, 1 )]]];

	// 按模板计算坐标
	var calcTetris = function( mode, direct, x, y ) {
		var rst = [];
		foreach( cycAt( cycAt( B4_TMPLS, mode ), direct ), function( co ) {
					add2list( rst, {
								x : x + co.x,
								y : y + co.y
							} );
				} );
		return rst;
	};

	program( {
				title : "Tetris", // 程序标题
				icon : "img/Tetris.png", // 程序图标
				// 窗口初始位置
				windowAttr : {
					height : APP_HEIGHT + 20,
					width : APP_WIDTH,
					left : 100,
					top : 100,
					// 能不能最大化
					canMax : false,
					// 能不能resize
					canResize : false,
					// 标题
					title : "Tetris"
				},
				// 启动回调
				onLoad : function( body ) {
					// 循环变量
					var i;
					var j;
					var k;

					// 应用程序区域
					var appA = body.area( {
								width : APP_WIDTH,
								height : APP_HEIGHT
							} );
					// 标题区域
					var titleA = appA.area( {
								left : GAP,
								top : GAP,
								width : TITLE_WIDTH,
								height : TITLE_HEIGHT,
								zIndex : GAP
							} );
					// 游戏区域
					var gameA = appA.area( {
								left : GAP,
								top : GAP + TITLE_HEIGHT + GAP,
								width : GAME_WIDTH,
								height : GAME_HEIGHT,
								zIndex : GAP
							} );
					// 计分板区域
					var scoreA = appA.area( {
								left : GAP + GAME_WIDTH + GAP,
								top : GAP + TITLE_HEIGHT + GAP,
								width : SCORE_WIDTH,
								height : SCORE_HEIGHT,
								zIndex : GAP
							} );

					// 应用程序背景图
					var appBG = Box( appA, {
								background_color : "#F0F0F0",
								left : 0,
								top : 0,
								width : APP_WIDTH,
								height : APP_HEIGHT,
								zIndex : GAP / 2
							} );

					// 游戏背景图
					var gameBG = Box( gameA, {
								background_color : "#C0C0C0",
								border_color : "#000000",
								left : 0,
								top : 0,
								width : GAME_WIDTH,
								height : GAME_HEIGHT,
								zIndex : GAP / 2
							} );

					// 砖
					var bric = function( x, y, color ) {
						var br = Box( gameA, {
									background_color : color,
									border_color : "#404040",
									border_width : "1px",
									left : x * BRIC_WIDTH,
									top : y * BRIC_HEIGHT,
									width : BRIC_WIDTH - 2,
									height : BRIC_HEIGHT - 2,
									zIndex : GAP / 2 + 1
								} );
						return {
							getX : function() {
								return x;
							},
							getY : function() {
								return y;
							},
							getColor : function() {
								return color;
							},
							remove : function() {
								br.remove();
							}
						};
					};
					// 4块砖
					var buildTetris = function( mode, direct, x, y, color ) {
						var rst = [];
						foreach( calcTetris( mode, direct, x, y ), function( co ) {
									add2list( rst, bric( co.x, co.y, color ) );
								} );
						return rst;
					};
					// 清理砖
					var clean = function( bli ) {
						foreach( bli, function( b ) {
									b.remove();
								} );
					};

					// 下落记录
					var drop = {
						// 模板
						mode : 0,
						// 方向
						direct : 0,
						// 坐标
						x : 0,
						y : 0,
						// 颜色
						color : "",
						// 实体
						brics : []
					};
					// 基底记录
					var base = {
						layers : [],
						fulls : [],
						rank : 0
					};
					// Tetris运动
					var go = function( op ) {
						// 下一步坐标
						var next = {
							"up" : {
								x : drop.x,
								y : drop.y,
								direct : drop.direct + 1
							},
							"down" : {
								x : drop.x,
								y : drop.y + 1,
								direct : drop.direct
							},
							"left" : {
								x : drop.x - 1,
								y : drop.y,
								direct : drop.direct
							},
							"right" : {
								x : drop.x + 1,
								y : drop.y,
								direct : drop.direct
							}
						};
						// 判断是否接受
						var accepted = true;
						foreach( calcTetris( drop.mode, next[op].direct, next[op].x, next[op].y ), function( co ) {
									if ( co.x < 0 || co.y < 0 || co.x >= LOGIC_WIDTH || co.y >= LOGIC_HEIGHT ) {
										accepted = false;
									}
									foreach( base.layers, function( l ) {
												foreach( l, function( b ) {
															if ( co.x == b.getX() && co.y == b.getY() ) {
																accepted = false;
															}
														} );
											} );
								} );
						// 接受则重构
						if ( accepted ) {
							drop.x = next[op].x;
							drop.y = next[op].y;
							drop.direct = next[op].direct;
							clean( drop.brics );
							drop.brics = buildTetris( drop.mode, drop.direct, drop.x, drop.y, drop.color );
							return true;
						}
						else {
							return false;
						}
					};

					// 游戏阶段
					var STAT = {
						OVER : 0,
						DROP : 1,
						RENEW : 2,
						HIGHLIGHT : 3,
						CREDIT : 4
					};
					var stat = STAT.OVER;
					// 分数
					var score = 0;
					// 计分板
					var scoreL = Label( scoreA, {
								left : 0,
								top : 0,
								text : "",
								font_size : "36px"
							} );
					// 游戏逻辑：下落、得分、更新
					var logic = [
							// over
							function() {

					},
							// drop
							function() {
								if ( !go( "down" ) ) {
									// 停止下落
									stat = STAT.CREDIT;
								}
							},
							// renew
							function() {
								// 选择新块
								drop.mode = drop.mode + 1;
								drop.color = "#808080";
								// 初始化位置
								drop.direct = 0;
								drop.x = LOGIC_WIDTH / 2 - 1;
								drop.y = 0;
								// 砍掉重练
								drop.brics = buildTetris( drop.mode, drop.direct, drop.x, drop.y, drop.color );

								// 立即执行下一步
								stat = STAT.DROP;
								logic[stat]();
							},
							// highlight
							function() {
								// 加分
								var ds = 1;
								loop( base.rank, function() {
											ds = ds * 5;
										} );
								score += ds / 5;
								scoreL.text( score.toString() );
								base.rank = 0;

								// 消除满行

								// 添加不满行
								var nls = [];
								foreach( base.layers, function( l ) {
											if ( l.length != LOGIC_WIDTH ) {
												var bs = [];
												foreach( l, function( b ) {
															add2list( bs, bric( b.getX(), LOGIC_HEIGHT - 1 - nls.length, b.getColor() ) );
														} );
												add2list( nls, bs );
											}
										} );
								// 清理原有砖
								clean( base.fulls );
								base.fulls = [];
								foreach( base.layers, function( l ) {
											clean( l );
										} );
								base.layers = nls;

								// 立即执行下一步
								stat = STAT.RENEW;
								logic[stat]();
							},
							// credit
							function() {
								// 将下落块合并进积累块
								foreach( drop.brics, function( b ) {
											var index = LOGIC_HEIGHT - 1 - b.getY();
											base.layers[index] = base.layers[index] || [];
											add2list( base.layers[index], b );
										} );
								drop.brics = [];
								// 处理填满的列
								base.fulls = [];
								foreach( base.layers, function( l ) {
											if ( l.length == LOGIC_WIDTH ) {
												loop( LOGIC_WIDTH, function( x ) {
															add2list( base.fulls, bric( x, l[0].getY(), "#FFFFFF" ) );
														} );
												base.rank = base.rank + 1;
											}
										} );

								// 有消除则高亮
								if ( base.rank > 0 ) {
									stat = STAT.HIGHLIGHT;
								}
								// 顶格则结束
								else if ( base.layers.length >= LOGIC_HEIGHT ) {
									turn.stop();
									alert( "game over" );
									stat = STAT.OVER;
								}
								// 否则直接新开始
								else {
									// 立即执行下一步
									stat = STAT.RENEW;
									logic[stat]();
								}
							}];
					// 定时逻辑
					var turn = body.Timer( function() {
								logic[stat]();
							}, 1000 );

					// 按键逻辑
					var move = {
						"left" : body.Timer( function() {
									if ( stat == STAT.DROP ) {
										go( "left" );
									}
								}, 50 ),
						"right" : body.Timer( function() {
									if ( stat == STAT.DROP ) {
										go( "right" );
									}
								}, 50 )
					};
					body.onKeydown( function( e ) {
								switch ( e.keyCode ) {
									case UP_KEY :
										if ( stat == STAT.DROP ) {
											go( "up" );
										}
										break;
									case LEFT_KEY :
										move["left"].start();
										break;
									case RIGHT_KEY :
										move["right"].start();
										break;
								}
							} );
					body.onKeyup( function( e ) {
								switch ( e.keyCode ) {
									case LEFT_KEY :
										move["left"].stop();
										break;
									case RIGHT_KEY :
										move["right"].stop();
										break;
								}
							} );

					// 定时加速
					var accelerater = body.Timer( function() {
								logic[stat]();
							}, 50 );
					// 下键按住加速
					body.onKeydown( function( e ) {
								switch ( e.keyCode ) {
									case DOWN_KEY :
										accelerater.start();
										break;
								}
							} );
					body.onKeyup( function( e ) {
								switch ( e.keyCode ) {
									case DOWN_KEY :
										accelerater.stop();
										break;
								}
							} );

					// 重置按钮
					var btnReset = Box( titleA, {
								background_color : "#00FF00",
								border_radius : BRIC_WIDTH / 2 + "px",
								left : 0,
								top : 0,
								width : BRIC_WIDTH,
								height : BRIC_WIDTH,
								zIndex : GAP / 2,
								onClick : function() {
									// 停止
									turn.stop();

									// 重置下落块
									clean( drop.brics );
									drop.brics = [];
									// 重置积累块
									clean( base.fulls );
									base.fulls = [];
									foreach( base.layers, function( l ) {
												clean( l );
											} );
									base.layers = [];
									// 清零积分
									score = 0;
									scoreL.text( "0" );

									// 开始
									stat = STAT.RENEW;
									turn.start();
								}
							} );
				}
			} );

	program( {
				title : "Demo", // 程序标题
				icon : "img/demo.gif", // 程序图标
				// 窗口初始位置
				windowAttr : {
					height : 400,
					width : 400,
					left : 100,
					top : 100,
					// 能不能最大化
					canMax : true,
					// 能不能resize
					canResize : true,
					// 标题
					title : "Hello"
				},
				// 启动回调
				onLoad : function( form ) {
					// form里是有Timer的

					// 创建一个白色背景
					var background = Z.element.Box( form, {
								background_color : "white"
							} );

					// 在from上,创建一个label
					var label = Z.element.Label( form, {
								font_size : "50px"
							} );

					// form等宽高
					form.onResize( function( event ) {
								background.width( event.width );
								background.height( event.height );
								label.text( "尺寸变化 " + event.width + " * " + event.height );
							} );

					// keydown事件
					form.onKeydown( function() {
								// 改变窗口的宽和高
								form.width( form.getWidth() + 10 );
								form.height( form.getHeight() + 10 );
							} );

					// 获得焦点事件
					form.onFocus( function() {
								label.text( "获得焦点" );
							} );
					form.onUnfocus( function() {
								label.text( "失去焦点" );
							} );

					// 最大化事件
					form.onMax( function() {
								label.text( "最大化" );
							} );
					form.onUnmax( function() {
								label.text( "去最大化" );
							} );

					// form的init事件,在load完窗口后,首先会触发resize事件,之后是focus事件,最后是init事件
					form.onInit( function() {
								label.text( "创建窗口完成" );
							} );
				}
			} );
} )();